package com.fengye.security.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;

import java.util.Collection;

@Slf4j
public class RoleBasedVoter implements AccessDecisionVoter<Object> {

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
        if(authentication == null) {
            return ACCESS_DENIED; // -1 反对
        }
        int result = ACCESS_ABSTAIN; // 0 弃权

        // 获取当前用户的所有权限,这是在UserDetailsService定义的用户权限
        Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
        log.info("当前认证用户信息: {}", authentication);
        log.info("当前认证用户在定义时所附带的权限信息: {}", authorities);
        FilterInvocation fi = (FilterInvocation) object;
        String url = fi.getRequestUrl(); // 获取当前的url
        String method = fi.getRequest().getMethod();
        log.info("当前请求的url为: {}, method: {}", url, method);
        // 遍历在WebSecurityConfig中定义的权限
        for (ConfigAttribute attribute : attributes) {
            log.info("WebSecurityConfig中和使用注解定义的权限: {}", attribute);
            if(attribute.getAttribute()==null){
                continue;
            }
            if (this.supports(attribute)) {
                result = ACCESS_DENIED;

                // Attempt to find a matching granted authority
                for (GrantedAuthority authority : authorities) {
                    if (attribute.getAttribute().equals(authority.getAuthority())) {
                        return ACCESS_GRANTED; // 赞成
                    }
                }
            }
        }

        return result;
    }

    Collection<? extends GrantedAuthority> extractAuthorities(
        Authentication authentication) {
        return authentication.getAuthorities();
    }

    @Override
    public boolean supports(Class clazz) {
        return true;
    }
}